/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Model;

import factory.PieceFactory;
import ObserveTools.MessagePlateau;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;

/**
 *
 * @author Bart-Home
 */
public class Plateau extends Observable {

    private Joueur joueurBlanc, joueurNoir;
    private Case[][] cases;
    private String tour = "blanc";
    //définition de mon factory qui créera
    private ArrayList<Observer> Obs;
    private boolean rafleOn = false;
    private int rafleCoordX, rafleCoordY = 0;

    public Case[][] getCases() {
        return cases;
    }

    public void setCases(Case[][] cases) {
        this.cases = cases;
    }

    public Plateau(Joueur joueurb, Joueur joueurn) {
        this.Obs = new ArrayList();
        this.joueurBlanc = joueurb;
        this.joueurNoir = joueurn;
        this.cases = new Case[10][5];

        int i, j, indice;
        for (i = 0; i < this.cases.length; i++) {
            for (j = 0; j < this.cases[i].length; j++) {
                indice = j;

                this.cases[i][j] = new Case(i, indice);
                if (i <= 3) {
                    Piece p = null;
                    p = PieceFactory.getPiece("pion", "noir");
                    this.cases[i][j].setOccupant(p);
                }
                if (i >= 6) {
                    Piece p = null;
                    p = PieceFactory.getPiece("pion", "blanc");
                    this.cases[i][j].setOccupant(p);
                }

            }
        }
    }

    /**
     * Procédure d'affichage du terrain en mode texte
     */
    public void affter() {
        int i, j = 0;
        String couleurOccupant;
        char occupant = '#';
        System.out.println("Affichage du terrain");
//        for (i = 0; i < this.cases.length; i++) {
//            System.out.print(" -");
//        }
//        System.out.print("\n");
        for (i = 0; i < this.cases.length; i++) {
            for (j = 0; j < this.cases[i].length; j++) {


                if (cases[i][j].getOccupant() == null) {
                    occupant = 'X';
                } else {
                    couleurOccupant = cases[i][j].couleurOccupant();
                    if (couleurOccupant.equals("noir")) {
                        occupant = 'N';
                    }
                    if (couleurOccupant.equals("blanc")) {
                        occupant = 'B';
                    }
                }

                if (i % 2 == 0) {

                    System.out.print("|" + occupant + "| ");
                } else {
                    System.out.print("| |" + occupant);
                }
            }
            System.out.print("|\n");
//            for (j = 0; j < this.cases.length; j++) {
//                System.out.print(" -");
//            }
//            System.out.print("\n");
        }
        System.out.println("Raffle" + rafleOn);
        System.out.println("Fin");
    }

    /**
     * Deplace la pièce se trouvant dans dep à la case arr. Elle appelle les autres fonction pour vérifier que cela est possible
     */
    public void deplacer(Case dep, Case arr) {
        System.out.println("Déplacer du plateau");

        if (dep.getOccupant() == null) {
            System.out.println("Case de depart vide");
            notifyObservers(new MessagePlateau(null, 2));
            return;
        }

        if (!(dep.couleurOccupant().equalsIgnoreCase(this.tour))) {
            System.out.println("Ce n'est pas votre tour");
            notifyObservers(new MessagePlateau(null, 1));
            return;
        }
        if (rafleOn) {
            if (dep.getCoordX() == rafleCoordX && dep.getCoordY() == rafleCoordY) {
                Case proie = dep.isAccessibleEnMangeant(arr);
                if (proie.getOccupant() == null) {
                    System.out.println("Case d'arrivée innaccessible. X " + arr.getCoordX() + " Y " + arr.getCoordY());
                    notifyObservers(new MessagePlateau(null, 3));
                    return;
                } else {
                    manger(dep, this.cases[proie.getCoordX()][proie.getCoordY()], arr);
                }
            } else {
                System.out.println("Vous devez manger avec le meme jeton");
                notifyObservers(new MessagePlateau(null, 4));
            }
        } else {
            if (dep.isAccessible(arr, dep.couleurOccupant())) {
                if (arr.getOccupant() != null) {
                    System.out.println("Case d'arrivée occupée  x " + arr.getCoordX() + " y " + arr.getCoordY());
                    notifyObservers(new MessagePlateau(null, 5));
                    return;
                } else {
                    this.cases[arr.getCoordX()][arr.getCoordY()].setOccupant(dep.getOccupant());
                    this.cases[dep.getCoordX()][dep.getCoordY()].setOccupant(null);
                    Case[] CaseChange = new Case[2];
                    CaseChange[0] = this.cases[dep.getCoordX()][dep.getCoordY()];
                    CaseChange[1] = this.cases[arr.getCoordX()][arr.getCoordY()];
                    notifyObservers(new MessagePlateau(CaseChange, 0));
                    this.affter();
                    this.changeTour(arr);
                    return;
                }
            } else {
                Case proie = dep.isAccessibleEnMangeant(arr);
                if (proie.getOccupant() == null) {
                    System.out.println("Case d'arrivée innaccessible. X " + arr.getCoordX() + " Y " + arr.getCoordY());
                    notifyObservers(new MessagePlateau(null, 3));
                    return;
                } else {
                    manger(dep, this.cases[proie.getCoordX()][proie.getCoordY()], arr);
                }
            }
            //this.affter();

        }
    }

    /**
     * Lors d'un appel a deplacer(), il se peut que l'on doive manger une pièce. Cette fonction s'occupe de faire les verifications nécessare
     */
    public void manger(Case dep, Case proie, Case arr) {
        //! Verifie que le pion en case dep peut manger le pion en case proie en arrivant casse arr
        if (dep.getOccupant() == null || proie.getOccupant() == null || arr.getOccupant() != null) {
            System.out.println("Erreur d'occupation");
            System.out.println(dep);
            System.out.println(proie);
            System.out.println(arr);
            notifyObservers(new MessagePlateau(null, 6));
            return;
        }
        boolean coulAttaquant = dep.isCouleurOccupantWhite();
        boolean coulProie = proie.isCouleurOccupantWhite();

        if (coulAttaquant != coulProie) {
            this.cases[arr.getCoordX()][arr.getCoordY()].setOccupant(dep.getOccupant());
            System.out.println("couleur arrivée : " + this.cases[arr.getCoordX()][arr.getCoordY()].couleurOccupant());
            // getOccupant(this.cases[arr.getCoordX()][arr.getCoordY()]).setCoordX(arr.getCoordX());
            // getOccupant(this.cases[arr.getCoordX()][arr.getCoordY()]).setCoordY(arr.getCoordY());
            this.cases[dep.getCoordX()][dep.getCoordY()].setOccupant(null);
            // getOccupant(this.cases[proie.getCoordX()][proie.getCoordY()]).meurt();
            if (this.cases[proie.getCoordX()][proie.getCoordY()].isCouleurOccupantWhite()) {
                joueurBlanc.perdUnePiece();
                String message = "Joueur Blanc : " + joueurBlanc.getPiecesRestantes() + " pion(s)";
                joueurBlanc.notifyObservers(message);
            } else {
                joueurNoir.perdUnePiece();
                String message = "Joueur Noir : " + joueurNoir.getPiecesRestantes() + " pion(s)";
                joueurNoir.notifyObservers(message);
            }
            this.cases[proie.getCoordX()][proie.getCoordY()].setOccupant(null);
            Case[] CaseChange = new Case[3];
            CaseChange[0] = this.cases[dep.getCoordX()][dep.getCoordY()];
            CaseChange[1] = this.cases[proie.getCoordX()][proie.getCoordY()];
            CaseChange[2] = this.cases[arr.getCoordX()][arr.getCoordY()];
            System.out.println("couleur a tester" + arr.getOccupant());
            if (peutmanger(this.cases[arr.getCoordX()][arr.getCoordY()])) {
                rafleOn = true;
                rafleCoordX = arr.getCoordX();
                rafleCoordY = arr.getCoordY();
            } else {
                rafleOn = false;

                this.changeTour(arr);
            }
            notifyObservers(new MessagePlateau(CaseChange, 0));
            /*On vient de manger un pion,
            CaseChange contient les trois cases qui viennent de changerpour avertir la vue,
            Code erreur 0 => execution normale*/
        } else {
            System.out.println("Vous ne pouvez pas manger un pion de votre équipe");
            notifyObservers(new MessagePlateau(null, 7));
        }



    }

    /**
     * Cette méthode permet de savoir si une case peut manger ou non
     */
    public boolean peutmanger(Case dep) {
        //! Verrifie si le pion peut manger pour faire une rafle
        if (dep.getCoordX() + 2 <= 9 && dep.getCoordY() + 1 <= 4) {
            if (cases[dep.getCoordX() + 2][dep.getCoordY() + 1].getOccupant() == null) {

                if (cases[dep.getCoordX() + 1][dep.getCoordY() + (dep.getCoordX() % 2)].getOccupant() != null
                        && cases[dep.getCoordX() + 1][dep.getCoordY() + (dep.getCoordX() % 2)].isCouleurOccupantWhite() != dep.isCouleurOccupantWhite()) {
                    return true;
                }
            }
        }
        if (dep.getCoordX() - 2 >= 0 && dep.getCoordY() + 1 <= 4) {
            if (cases[dep.getCoordX() - 2][dep.getCoordY() + 1].getOccupant() == null) {
                if (cases[dep.getCoordX() - 1][dep.getCoordY() + (dep.getCoordX() % 2)].getOccupant() != null
                        && cases[dep.getCoordX() - 1][dep.getCoordY() + (dep.getCoordX() % 2)].isCouleurOccupantWhite() != dep.isCouleurOccupantWhite()) {
                    return true;
                }
            }
        }
        if (dep.getCoordX() + 2 <= 9 && dep.getCoordY() - 1 >= 0) {

            if (cases[dep.getCoordX() + 2][dep.getCoordY() - 1].getOccupant() == null) {
                //S'assurer que dep.getcoord + x ne depasse pas les valeurs du tableau
                if (cases[dep.getCoordX() + 1][dep.getCoordY() - 1 + (dep.getCoordX() % 2)].getOccupant() != null
                        && cases[dep.getCoordX() + 1][dep.getCoordY() - 1 + (dep.getCoordX() % 2)].isCouleurOccupantWhite() != dep.isCouleurOccupantWhite()) {
                    return true;

                }
            }
        }
        if (dep.getCoordX() - 2 >= 0 && dep.getCoordY() - 1 >= 0) {
            if (cases[dep.getCoordX() - 2][dep.getCoordY() - 1].getOccupant() == null) {
                if (cases[dep.getCoordX() - 1][dep.getCoordY() - 1 + (dep.getCoordX() % 2)].getOccupant() != null
                        && cases[dep.getCoordX() - 1][dep.getCoordY() - 1 + (dep.getCoordX() % 2)].isCouleurOccupantWhite() != dep.isCouleurOccupantWhite()) {
                    return true;

                }
            }
        }

        return false;
    }

    /**
     * Cette méthode permet d'ajouter des observer
     */
    public void addObserver(Observer obs) {
        this.Obs.add(obs);
    }

    /**
     * Cette méthode permet de supprimer un observateur
     */
    public void deleteObserver() {
        this.Obs = null;
    }

    /**
     * Cette méthode demande la mise à jour de la vue
     */
    public void notifyObservers(MessagePlateau Mess) {
        Iterator it = Obs.iterator();
        Observer obs = null;
        while (it.hasNext()) {
            obs = (Observer) it.next();
            obs.update(this, Mess);
        }
        //System.out.println("Notifier : "+Case+" num erreur : "+erreur);
    }

    /**
     * Cette fonction est appellée a la fin d'un tour d'un joueur, quand il ne peut plus déplacer sa pièce.
     * C'est cette fonction qui donne la main a l'autre joueur après avoir vérifier si la pièce qui vient de bouger se transforme en dame et avoir tester si un joueur a perdu
     */
    public void changeTour(Case arr) {
        if (arr.getCoordX() == 0) {
            if (this.cases[arr.getCoordX()][arr.getCoordY()].isCouleurOccupantWhite()) {
                this.cases[arr.getCoordX()][arr.getCoordY()].setOccupant(null);
                Piece p = PieceFactory.getPiece("dame", "blanc");
                this.cases[arr.getCoordX()][arr.getCoordY()].setOccupant(p);
                Case[] CaseChange = new Case[1];
                CaseChange[0] = new Case(this.cases[arr.getCoordX()][arr.getCoordY()]);
                notifyObservers(new MessagePlateau(CaseChange, 8));
            }
        }

        if (arr.getCoordX() == 9) {
            if (!this.cases[arr.getCoordX()][arr.getCoordY()].isCouleurOccupantWhite()) {
                this.cases[arr.getCoordX()][arr.getCoordY()].setOccupant(null);
                Piece p = PieceFactory.getPiece("dame", "noir");
                this.cases[arr.getCoordX()][arr.getCoordY()].setOccupant(p);
                Case[] CaseChange = new Case[1];
                CaseChange[0] = new Case(this.cases[arr.getCoordX()][arr.getCoordY()]);
                notifyObservers(new MessagePlateau(CaseChange, 8));
            }
        }

        if (this.tour.equalsIgnoreCase("noir")) {
            if (this.joueurBlanc.getPiecesRestantes() == 0) {
                this.joueurNoir.notifyObservers("Joueur Noir : Vainqueur");
                this.joueurBlanc.notifyObservers("Joueur Blanc : t'as perdu tocard");
                System.out.println("Joueur Noir Vainqueur");
            } else {
                notifyObservers(new MessagePlateau(null, 9));
                this.tour = "blanc";
            }
        } else if (this.tour.equalsIgnoreCase("blanc")) {
            if (this.joueurNoir.getPiecesRestantes() == 0) {
                this.joueurNoir.notifyObservers("Joueur Noir : t'as perdu tocard");
                this.joueurBlanc.notifyObservers("Joueur Blanc : Vainqueur");
                System.out.println("Joueur Blanc Vainqueur");
            } else {
                notifyObservers(new MessagePlateau(null, 10));
                this.tour = "noir";
            }
        }
    }
}
